#ifndef __BUOLA_GUI_CACCELERATOR_H__
#define __BUOLA_GUI_CACCELERATOR_H__

#include <buola/gui.h>
#include <buola/utility/uevent.h>
#include <buola/gui/tkey.h>

namespace buola { namespace gui {

///\addtogroup gui
///@{

////////////////////////////////////////////////////////////////////////////

/// keyboard shortcut

/// Objects of this class make it possible to receive an event when a key
/// is pressed, independent of the normal dispatching of key events to the
/// focused window.
///
/// There are two ways to get these events
/// - Getting it dispatched to a window as if the window had the focus
/// - By connecting to the eTriggered event of the accelerator
///
/// \todo allow more than one accelerator on the same key combination
///
////////////////////////////////////////////////////////////////////////////

class CAccelerator : public UUncopiable
{
public:
    //! accelerator flags
    enum EFlags
    {
        GLOBAL=(1<<0),      //!< active regardless of the focus
        APPLICATION=(1<<1),//!< active if the focus is within the application
        TOPLEVEL=(1<<2),    //!< active if the focus in within the top-level window
        LOCAL=(1<<3),       //!< active only if the focus is in the window
        PROCESSNORMAL=(1<<4)//!< also process the key event normally
    };

    DECLARE_FRIEND_ENUM_BITOPS(EFlags)

//! \name constructor and destructor
//@{
    //! just creates the object, without initializing it
    CAccelerator()
    {
        mValid=false;
        mAllAccelerators.push_back(this);
    }

    //! creates the object and sets up the keyboard shortcut
    CAccelerator(const TKey &pKey,EKeyMod pMods,EFlags pFlags=APPLICATION,const PWindow &pWindow=nullptr)
    {
        mValid=false;
        mAllAccelerators.push_back(this);
        Set(pKey,pMods,pFlags,pWindow);
    }

    //! destroys the object and unsets the shortcut
    ~CAccelerator()
    {
        if(mValid) Unset();
        mAllAccelerators.erase(std::find(mAllAccelerators.begin(),
                        mAllAccelerators.end(),this));
    }
//@}

//! \name public interface
//@{
    ///sets the accelerator
    void Set(const TKey &pKey,EKeyMod pMods,EFlags pFlags=APPLICATION,const PWindow &pWindow=nullptr);
    ///unsets the accelerator
    void Unset();

    //! get a string representing the key combination
    std::wstring GetKeyName();
//@}

    //! tries to dispatch a key event via accelerators
    static bool Dispatch(CKeyEvent&);

private:
    //! check if the key event should be dispatched by this accelerator
    bool Check(const CKeyEvent&);

public:
    //! will be dispatched when the key combination is pressed
    UEvent<void()> eTriggered;

private:
    bool mValid;

    TKey mKey;
    EKeyMod mMods;
    EFlags mFlags;
    CWindow *mWindow;

    static std::vector<CAccelerator*> mAllAccelerators;
};

///@}

/*namespace gui*/ } /*namespace buola*/ }

#endif
